using System;
using System.Collections.Generic;
using System.Text;
using WMFSDKWrapper;    //managed wrapper to WMF SDK - provides access to metadata

namespace WMFMetadataReader
{
    /// This class contains the functionality for handling interaction with the media file
    /// metadata, via the WMF SDK managed wrapper class.
    public class MetaDataReader
    {

        /// Default constructor
        public MetaDataReader()
        {
        }

        public byte[] GetFieldByteArrayByName(string fileName, string attrName)
        {
            try
            {
                IWMMetadataEditor MetadataEditor;   //object used to access WMF file 
                IWMHeaderInfo3 HeaderInfo3;         //object to use access metadata 
                ushort streamNum = 0;               //media stream to interrogate
                WMT_ATTR_DATATYPE wAttribType;      //data type of attribute
                byte[] pbAttribValue = null;        //value of attribute (as returned by method call)
                ushort wAttribValueLen = 0;         //length of attribute (byte array)

                WMFSDKFunctions.WMCreateEditor(out MetadataEditor);

                MetadataEditor.Open(fileName);

                HeaderInfo3 = (IWMHeaderInfo3)MetadataEditor;

                //make call to get attribute length
                HeaderInfo3.GetAttributeByName(ref streamNum, attrName, out wAttribType, pbAttribValue, ref wAttribValueLen);
                //set byte array length
                pbAttribValue = new byte[wAttribValueLen];
                //make call again, which will get value into correct-length byte array
                HeaderInfo3.GetAttributeByName(ref streamNum, attrName, out wAttribType, pbAttribValue, ref wAttribValueLen);

                MetadataEditor.Close();

                return (pbAttribValue);
                //return ConvertAttrToString(pbAttribValue, wAttribValueLen);
            }
            catch (Exception e)
            {
                throw e;
            }
        }//end method

        /// Method to obtain a metadata attribute by passing in its name. 
        /// Assumes the metadata type is STRING.
        /// Uses the SDK function GetAttributeByName.
        ///
        /// param name="filename" - the filename (including path) of media file to interrogate
        /// param name="attrName" - the name of the field we're looking for
        /// returns - the value of the named attribute, empty string if not found, or error message
        public string GetFieldByName(string fileName, string attrName)
        {
            try
            {
                IWMMetadataEditor MetadataEditor;   //object used to access WMF file 
                IWMHeaderInfo3 HeaderInfo3;         //object to use access metadata 
                ushort streamNum = 0;               //media stream to interrogate
                WMT_ATTR_DATATYPE wAttribType;      //data type of attribute
                byte[] pbAttribValue = null;        //value of attribute (as returned by method call)
                ushort wAttribValueLen = 0;         //length of attribute (byte array)

                WMFSDKFunctions.WMCreateEditor(out MetadataEditor);

                MetadataEditor.Open(fileName);

                HeaderInfo3 = (IWMHeaderInfo3)MetadataEditor;

                //make call to get attribute length
                HeaderInfo3.GetAttributeByName(ref streamNum, attrName, out wAttribType, pbAttribValue, ref wAttribValueLen);
                //set byte array length
                pbAttribValue = new byte[wAttribValueLen];
                //make call again, which will get value into correct-length byte array
                HeaderInfo3.GetAttributeByName(ref streamNum, attrName, out wAttribType, pbAttribValue, ref wAttribValueLen);

                MetadataEditor.Close();

                return ConvertAttrToString(pbAttribValue, wAttribValueLen);
            }
            catch (Exception e)
            {
                return "ERROR: " + e.Message;
            }
        }//end method

        /// Method to convert byte array value into string. 
        /// (From the Microsoft WMF SDK sample.)
        ///
        /// param name="pbValue" - byte array value of attribute
        /// param name="dwValueLen" - Length of byte array
        private string ConvertAttrToString(byte[] pbValue, ushort dwValueLen)
        {
            string Value = "";

            if (0 == dwValueLen)
            {
                Value = "";
            }
            else
            {
                if ((0xFE == Convert.ToInt16(pbValue[0])) &&
                     (0xFF == Convert.ToInt16(pbValue[1])))
                {
                    Value = "UTF-16LE BOM+";

                    if (4 <= dwValueLen)
                    {
                        for (int i = 0; i < pbValue.Length - 2; i += 2)
                        {
                            Value += Convert.ToString(BitConverter.ToChar(pbValue, i));
                        }
                    }
                }
                else if ((0xFF == Convert.ToInt16(pbValue[0])) &&
                          (0xFE == Convert.ToInt16(pbValue[1])))
                {
                    Value = "UTF-16BE BOM+";
                    if (4 <= dwValueLen)
                    {
                        for (int i = 0; i < pbValue.Length - 2; i += 2)
                        {
                            Value += Convert.ToString(BitConverter.ToChar(pbValue, i));
                        }
                    }
                }
                else
                {
                    Value = "";
                    if (2 <= dwValueLen)
                    {
                        for (int i = 0; i < pbValue.Length - 2; i += 2)
                        {
                            Value += Convert.ToString(BitConverter.ToChar(pbValue, i));
                        }
                    }
                }
            }//end else not a 0-length string

            return Value;

        }//end method

    }//end class

}
